package org.origin.centre.security.authentication.handlers;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.origin.centre.utils.ResponseUtil;
import org.origin.centre.support.utils.BasicUtil;
import org.origin.centre.support.utils.ConvertUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
import org.springframework.security.oauth2.core.endpoint.DefaultOAuth2AccessTokenResponseMapConverter;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.time.temporal.ChronoUnit;
import java.util.Map;

/**
 * 登录认证成功处理器
 *
 * @author ferret
 * @version 2024-05-08
 */
public class IAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    /**
     * 日志记录器
     */
    private final static Logger logger = LoggerFactory.getLogger(IAuthenticationSuccessHandler.class);

    /**
     * 访问令牌响应参数转换器
     */
    protected Converter<OAuth2AccessTokenResponse, Map<String, Object>> accessTokenResponseParametersConverter = new DefaultOAuth2AccessTokenResponseMapConverter();

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        // 记录登录成功的日志信息
        logger.info("authentication login success：");

        // 获取认证成功的访问令牌认证对象
        OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = (OAuth2AccessTokenAuthenticationToken) authentication;

        // 获取访问令牌和刷新令牌
        OAuth2AccessToken accessToken = accessTokenAuthentication.getAccessToken();
        OAuth2RefreshToken refreshToken = accessTokenAuthentication.getRefreshToken();
        Map<String, Object> additionalParameters = accessTokenAuthentication.getAdditionalParameters();

        // 构建访问令牌响应
        OAuth2AccessTokenResponse.Builder builder = OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue())
                .tokenType(accessToken.getTokenType());

        // 如果访问令牌有发行时间和过期时间，则设置过期时间
        if (accessToken.getIssuedAt() != null && accessToken.getExpiresAt() != null) {
            builder.expiresIn(ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt()));
        }

        // 如果刷新令牌不为空，则添加刷新令牌
        if (refreshToken != null) {
            builder.refreshToken(refreshToken.getTokenValue());
        }

        // 如果附加参数不为空，则添加附加参数
        if (!CollectionUtils.isEmpty(additionalParameters)) {
            builder.additionalParameters(additionalParameters);
        }

        // 构建最终的访问令牌响应
        OAuth2AccessTokenResponse accessTokenResponse = builder.build();

        // 将访问令牌响应转换为参数映射
        Map<String, Object> tokenResponseParameters = this.accessTokenResponseParametersConverter.convert(accessTokenResponse);

        /**
         * 判断是否是Swagger请求，如果是则返回默认格式，否则返回成功响应
         */
        if (isSwaggerRequest(request)) {
            ResponseUtil.response(response, HttpStatus.OK, tokenResponseParameters);
        } else {
            ResponseUtil.success(response, "请求成功", tokenResponseParameters);
        }
    }

    /**
     * 判断是否是Swagger访问
     *
     * @param request HttpServletRequest对象，用于获取请求头和参数
     */
    public boolean isSwaggerRequest(HttpServletRequest request) {
        Integer resultType = ConvertUtil.getInteger(BasicUtil.getBlankVal(request.getHeader("resultType"), request.getParameter("resultType")));
        return null != resultType && resultType == 3;
    }
}